package toy.keli.picmap.model;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import toy.keli.picmap.util.utilJson;


//import javax.script.ScriptEngine;
//import javax.script.ScriptEngineManager;
//import javax.script.ScriptException;

/**
 * 类型汇总类（实现java弱类型） 思路来源于php zend引擎  
 * 
 * @author lishang
 */
public class def extends T implements  Iterable<def>,Iterator{
    public Types t;     //调试显示类型 
    public Object v;    //调试显示值
    public void upDebugShow(Types t0,Object v0){
        t=t0;v=v0;
    }
    public def(){
        this.type=Types.IS_NULL;
        this.value=new zend_val();
        upDebugShow(this.type,null);
    }
    
    @Override
    public boolean hasNext() {
        boolean rt=false;
        if(this.type== Types.IS_ARRAY)
            rt=  index < this.value.aval.size();
        if(this.type== Types.IS_OBJECT){
            if(hkeys==null)    hkeys=this.value.hmval.keySet().iterator();
            rt=  hkeys.hasNext();
        }
        if(!rt && index>0) index=0;
        return rt;
    }
    
    public boolean reset(){
        index=0;
        return true;
    }
    
    @Override
    public Object next() {
        Object rt=null;
        if(this.type== Types.IS_ARRAY)  
            rt=  this.value.aval.get(index);
        if(this.type== Types.IS_OBJECT) {
            rt= hkeys.next();
        }
        index++;
        return def.valueOf(rt);
    }

    @Override
    public Iterator<def> iterator() {
        return this;
    }

    
     @Override
    public  void remove() {
        empyt();
    }
    public  void remove(int index) {
        this.value.aval.remove(index);
    }
    public  void remove(String key) {
        this.value.hmval.remove(key);
    }
    public boolean empyt() {
        this.index=0;
        this.type=Types.IS_NULL;
        this.value=new zend_val();
        upDebugShow(this.type,null);
        
        return true;
    }
    
    public boolean isEmpyt() {
        if(this.type==Types.IS_NULL) return true;
        return this.toString().isEmpty();
    }

    public def end() {
        int i=this.value.aval.size()-1;
        return  (def)this.value.aval.get(i);
    }

    public static class dict extends def {
        public dict(Object ...args){
            super();
            for(int i=0;i<args.length;i+=2)
                this.set(args[i],args[i+1]);
        }
    }
    public static class list extends def {
        public list(String ...args) {
            super();
            for(int i=0;i<args.length;i++)
                this.push(def.valueOf(args[i]));
        }
    }

    public static class map extends def {
        public map(Map<String, String> m) {
            super();
            for(String k:m.keySet()){
                this.set(k,m.get(k));
            }
        }
    }

    public class arrayByString extends def {
        public arrayByString(String text) {
            super();
            String[] a=text.split("\\n");
            for(int i=0;i<a.length;i++){
                if(a[i].trim().matches("\\s+")){
                    String[] b=text.split("\\s+",2);
                    this.set(b[0],b[1]);
                }else{
                    this.push(a[i]);
                }
            }
        }
    }
    public static class tree extends def {
        public tree(String text) {
            String[] mAll = text.split("\\n");
            init(mAll,0);
        }
        public tree(def c,int f){
            init(c.toStrings(),f);
        }
        void init(String []mAll,int f){
            def sub=new def();
            String key="";
            for(int i=0;i<mAll.length;i++){
                String name=mAll[i];
                String[] a = name.split("\\t");
                if(a.length <= f+1){
                    if(!key.equals(""))
                        this.set(key,sub.isEmpyt() ? key: new tree(sub,f+1));
                    key=name.trim();
                    sub.empyt();
                }else{
                    sub.push(name);
                }
            }
            this.set(key,sub.isEmpyt() ? key: new tree(sub,f+1));
        }
    }
    //算数表达式计算   https://zhuanlan.zhihu.com/p/38226118
    public static class expr extends def {
        public expr(String expression) {
            super();
//            try {
//                ScriptEngineManager manager = new ScriptEngineManager();
//                ScriptEngine se = manager.getEngineByName("js");
//                Double result = (Double) se.eval(expression);
//                //Double result=1.0;
//                this.type=Types.IS_DOUBLE;
//                this.value.dval=result;
//                this.upDebugShow(this.type,this.value.dval);
//            } catch (ScriptException ex) {
//                Logger.getLogger(var.class.getName()).log(Level.SEVERE, null, ex);
//            }
        }
    }
    public static class json extends def {
        public json(String expression) {
            super();
            utilJson.parse(expression,this);
        }
    }
    public String toJsonString() {
        return utilJson.toString(this);
    }
    public static def valueOf(Object v){
         if (v instanceof def)    return (def)v;
        
        def rt=new def();
        rt.value=new zend_val(v);
        if (v instanceof Integer) {
             rt.type= Types.IS_INT;
             rt.value.ival=Integer.parseInt(v.toString());
        } else if (v instanceof String) {
            rt.type= Types.IS_STRING;
            rt.value.sval=((String) v).toString();
        } else if (v instanceof Double) {
            rt.type= Types.IS_DOUBLE;
            rt.value.dval=Double.parseDouble( v.toString());
        } else if (v instanceof Float) {
            rt.type= Types.IS_LONG;
            rt.value.dval=Float.parseFloat(v.toString());
        } else if (v instanceof Long) {
            rt.type= Types.IS_LONG;
            rt.value.dval=Long.parseLong(v.toString());
        } else if (v instanceof Boolean) {
             rt.type= Types.IS_BOOL;
             rt.value.bval=Boolean.parseBoolean(v.toString());
        }else{
             if(v!=null){
                rt.type= Types.IS_OBJECT;
                rt.value.oval=v;
             }
        }        
        rt.upDebugShow(rt.type,rt.source());
        return rt;
    }

    public def get(String key) {
        if(this.value.hmval ==null && this.value.oval!=null)
            return new Reflection(this.value.oval).getField(key);
        if(this.value.aval.size()>0 && key.matches("\\d+")) return get(Integer.valueOf(key));
        def rt=(def)this.value.hmval.get(key);
        return rt!=null ? rt : new def();
    }
    public def get(int i) {
        def rt=(def)this.value.aval.get(i);
        return rt!=null ? rt : new def();
    }
    public def get(def i) {
        if(i.value.sval==null){
            return this.get(i.toInt());
        }else{
            return this.get(i.toString());
        }
    }
    
    public def pop() {
        int i=this.value.aval.size()-1;
        def rt= (def)this.value.aval.get(i);
        this.value.aval.remove(i);
        return rt;
    }
    public def shift() {
        def rt=(def)this.value.aval.get(0);
        this.value.aval.remove(0);
        return rt;
    }
    public def[]  values() {
        int size=this.size();
        def[] rt = new def[size];
        if(type == Types.IS_ARRAY) {
            for(int i=0;i<size;i++) rt[i]= (def)value.aval.get(i);
        }
        if(type == Types.IS_OBJECT) {
            int i=0;
            for(String name: value.hmval.keySet())         rt[i++]=(def)value.hmval.get(name);
        }
        return rt;
    }


    public boolean push(def v)  {
        if(this.type== Types.IS_NULL){
            this.type= Types.IS_ARRAY;
            upDebugShow(this.type, this.value.aval);
        }
        if(this.type!= Types.IS_ARRAY) return false; //throw new Exception("类型配置错误,变量是"+this.typeName()+"类型,无法push,只有数组类型才能push");
        return this.value.aval.add(v);
    }
    public boolean set(String key, def val) {
        if(this.type== Types.IS_NULL){
            this.type = Types.IS_OBJECT;
            upDebugShow(this.type, this.value.hmval);
        }
        if(this.type!= Types.IS_OBJECT) return false; //throw new Exception("类型配置错误,变量是"+this.typeName()+"类型,无法set,只有hash类型才能set");
        this.value.hmval.put(key,val);
        return true;
    }
    public boolean set(String key,Object val) {
        return this.set(key, def.valueOf(val));
    }
    public boolean set(Object key,Object val) {
        return this.set(key.toString(), def.valueOf(val));
    }
    public boolean push(Object v)  {
        return this.push(def.valueOf(v));
    }
    
    @Override
    public boolean equals(Object obj){
        return source().equals(obj);
//        def p=valueOf(obj);
//        return p.type==type && p.source().equals(obj);
    }
    //hash的键值置换
    public def flip(){
        def rt=new def();
        for(String k : this.value.hmval.keySet()){
            rt.set(this.value.hmval.get(k),k);
        }
        return rt;
    }
    public def slice(int i) {
        return slice(i,this.size()-1);
    }
    public def slice(int i, int len) {
        def rt=new def();
        if(len<0) len=this.size()-len-1;
        for(;i<len+i;i++){
            rt.push(this.get(i));
        }
        return rt;
    }
}

class T {
    protected enum Types{IS_NULL,IS_BOOL,IS_INT,IS_LONG,IS_DOUBLE,IS_STRING,IS_ARRAY,IS_OBJECT}
    public Types type;
    public zend_val value;
    protected int index=0;
    protected Iterator<String> hkeys;
//    private final char IS_NULL = 0;
//    private final char IS_BOOL = 1;
//    private final char IS_INT = 2;
//    private final char IS_LONG = 3;
//    private final char IS_DOUBLE = 4;
//    private final char IS_STRING = 5;
//
//    private final char IS_ARRAY = 6;
//    private final char IS_OBJECT = 7;

//匿名函数  https://www.jianshu.com/p/956a0464001c
    public interface IFunction{
        //    void call(T v,int i);
        void call(T value, String key);
    }
    //functionCaseClass.funcTest((arg)->System.out.println("a   "+arg));
    public void forEach(IFunction func){
        if(this.type== Types.IS_ARRAY) {
            for (int i = 0; i < this.value.aval.size(); i++)
                func.call(this.value.aval.get(i), String.valueOf(i));
        }else if(this.type== Types.IS_OBJECT) {
            for (String key : this.value.hmval.keySet()){
                func.call(this.value.hmval.get(key),key);
            }
        }
    }
    public String typeName() {
        String map[]={"null","bool","int","long","double","string","array","hash"};
        return map[type.ordinal()];
    }
    public Object source(){
        return value.get(type.ordinal());
    }
    public Object to(Class v) {
        Object rt=this.source();

        if (v.equals(int.class)) {
            return Integer.parseInt(rt.toString().length()>0? rt.toString():"0");
        } else if (v.equals(String.class)) {
            return (String) rt;
        } else if (v.equals(double.class)) {
            return  Double.parseDouble(rt.toString());
        } else if (v.equals(float.class)) {
            float f = Float.parseFloat(rt.toString());
            return f;
        } else if (v.equals(long.class)) {
            long l = Double.valueOf(rt.toString()).longValue();
            return l;
        } else if (v.equals(boolean.class)) {
            boolean b = Boolean.parseBoolean(rt.toString());
            return b;
        }
        return rt;
    }
    public void toObject(Object rt){
        Reflection r=new Reflection(rt);
        for(String k: this.value.hmval.keySet()) {
            r.setField(k, (def) this.value.hmval.get(k));
        }
    }
    //给对象类型用的  循环转换方法
    public Map<String,String> toHash(){
        HashMap<String,String> rt = new HashMap<String ,String>();
        if(this.type== Types.IS_OBJECT){
            try {
                Reflection r=new Reflection(this.value.oval);
                String[] attrs=r.getFields();
                Class C=this.value.oval.getClass();

                for(int i=0;i<attrs.length;i++) {
                    String key=attrs[i];
                    String val="";
                    Field field=C.getDeclaredField(key);
                    if(Modifier.isPublic(field.getModifiers())){
                        val=String.valueOf(field.get(this.value.oval));
                    }else {
                        String mname="get" + key.substring(0, 1).toUpperCase() + key.substring(1);
                        if(r.method_exists(mname)) {
                            val=r.method_call(mname).toString();
                        }else continue;
                    }
                    rt.put(key, val);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            return rt;
        }
        return null;
    }

    //数据类型的互相转换  https://www.cnblogs.com/mike-mei/p/11110051.html
    public String toString() {
        switch (this.type.ordinal()) {
            case 0:
                return null;
            case 1:
                return this.value.bval ? "1" : "0";
            case 2:
                return Integer.toString(this.value.ival);
            case 3:
            case 4:
                return Double.toString(this.value.dval);
            case 5:
                return this.value.sval;
            case 6:
                return "array(" + String.valueOf(this.value.aval.size()) + ")";
            case 7:
                if(this.value.hmval==null && this.value.oval!=null) return this.value.oval.toString();
                return "object(" + String.valueOf(this.value.hmval.size()) + ")";
        }

        return "";
    }

    String[] range(int n){
        String[] rt=new String[n];
        for(int i=0;i<n;i++)
            rt[i]=String.valueOf(i);
        return rt;
    }

    public String[] toStrings() {
        return toStrings(false);
    }
    public String[] toStrings(boolean hasKey) {
        String[] rt = new String[this.size()];
        String[] keys=(type == Types.IS_OBJECT)?  keys(): range(rt.length);
        for(int i=0;i<rt.length;i++){
            if(hasKey)
                rt[i]=(type == Types.IS_ARRAY) ? keys[i]+"\t:\t"+value.aval.get(i).toString(): keys[i]+"\t:\t"+value.hmval.get(keys[i]).toString();
            else
                rt[i]=(type == Types.IS_ARRAY) ? value.aval.get(i).toString(): value.hmval.get(keys()[i]).toString();
        }
        return rt;
    }
    public int toInt(){
        return this.toString()==null ? 0 : Integer.valueOf(this.toString()).intValue();
    }
    public long toLong(){
        return this.toString() == null ? 0 : Double.valueOf(this.toString()).longValue();
    }
    public float toFloat(){
        return this.toString()==null ? 0f: Double.valueOf(this.toString()).floatValue();
    }
    
    int length=0;
    public int size() {
        if(type == Types.IS_ARRAY) length= value.aval.size();
        else if(type == Types.IS_OBJECT) length= value.hmval.size();
        else length=-1;

        return length;
    }
    public String[] keys() {
        int size=this.size();
         String[] rt = new String[size];
        if(type == Types.IS_ARRAY) {
            for(int i=0;i<size;i++) rt[i]= String.valueOf(i);
        }
        if(type == Types.IS_OBJECT) {
            int i=0;
            for(String name: value.hmval.keySet())         rt[i++]=name;
        }
        return rt;
    }
    public boolean hasKey(String name) {
        return this.value.hmval.get(name)!=null;
    }

    public boolean exists(Object v) {
        int size=this.size();
        if(type == Types.IS_ARRAY) {
            for(int i=0;i<size;i++)
                if(value.aval.get(i).equals(v)) return true;
        }
        if(type == Types.IS_OBJECT) {
            int i=0;
            for(String name: value.hmval.keySet())
                if(value.hmval.get(name).equals(v)) return true;
        }
        return false;
    }
    public boolean unset(String key){
        this.value.hmval.remove(key);
        return true;
    }
    public boolean unset(int i){
        this.value.aval.remove(i);
        return true;
    }

    
    public static class zend_val{
        boolean bval;
        int ival;
        double dval;
        String sval;
        Object oval;

        List <T>aval;
        Map<String, T> hmval;

        public zend_val(Object v) {
//            if (v instanceof Integer) {
//                 this.ival=Integer.parseInt(v.toString());
//            } else if (v instanceof String) {
//                this.sval=((String) v).toString();
//            } else if (v instanceof Double) {
//                this.dval=Double.parseDouble( v.toString());
//            } else if (v instanceof Float) {
//                this.dval=Float.parseFloat(v.toString());
//            } else if (v instanceof Long) {
//                this.dval=Long.parseLong(v.toString());
//            } else if (v instanceof Boolean) {
//                 this.bval=Boolean.parseBoolean(v.toString());
//            }else{
//                 this.oval=v;
//            }
        }
        public zend_val() {
            aval=new ArrayList<T>();
            hmval=new LinkedHashMap<String, T>();
        }
        public Object get(int ordinal) {
            //private enum Types{IS_NULL,IS_BOOL,IS_INT,IS_LONG,IS_DOUBLE,IS_STRING,IS_ARRAY,IS_OBJECT}
            Object[] rt={null,bval,ival,dval,dval,sval,aval,oval};
            if(ordinal==7 && hmval!=null) return hmval;
            return rt[ordinal];
        }
    }
}



